home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / FS / FCNTL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-17  |  5.1 KB  |  244 lines

  1. /*
  2.  *  linux/fs/fcntl.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/mm.h>
  8. #include <linux/file.h>
  9. #include <linux/smp_lock.h>
  10.  
  11. #include <asm/uaccess.h>
  12.  
  13. extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
  14.  
  15. static inline int dupfd(unsigned int fd, unsigned int arg)
  16. {
  17.     struct files_struct * files = current->files;
  18.     struct file * file;
  19.     int error;
  20.  
  21.     error = -EINVAL;
  22.     if (arg >= NR_OPEN)
  23.         goto out;
  24.  
  25.     error = -EBADF;
  26.     file = fget(fd);
  27.     if (!file)
  28.         goto out;
  29.  
  30.     error = -EMFILE;
  31.     arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
  32.     if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
  33.         goto out_putf;
  34.     FD_SET(arg, &files->open_fds);
  35.     FD_CLR(arg, &files->close_on_exec);
  36.     fd_install(arg, file);
  37.     error = arg;
  38. out:
  39.     return error;
  40.  
  41. out_putf:
  42.     fput(file);
  43.     goto out;
  44. }
  45.  
  46. asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
  47. {
  48.     int err = -EBADF;
  49.  
  50.     lock_kernel();
  51.     if (!fcheck(oldfd))
  52.         goto out;
  53.     err = newfd;
  54.     if (newfd == oldfd)
  55.         goto out;
  56.     err = -EBADF;
  57.     if (newfd >= NR_OPEN)
  58.         goto out;    /* following POSIX.1 6.2.1 */
  59.  
  60.     sys_close(newfd);
  61.     err = dupfd(oldfd, newfd);
  62. out:
  63.     unlock_kernel();
  64.     return err;
  65. }
  66.  
  67. asmlinkage int sys_dup(unsigned int fildes)
  68. {
  69.     int ret;
  70.  
  71.     lock_kernel();
  72.     ret = dupfd(fildes, 0);
  73.     unlock_kernel();
  74.     return ret;
  75. }
  76.  
  77. #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
  78.  
  79. static int setfl(int fd, struct file * filp, unsigned long arg)
  80. {
  81.     struct inode * inode = filp->f_dentry->d_inode;
  82.  
  83.     /*
  84.      * In the case of an append-only file, O_APPEND
  85.      * cannot be cleared
  86.      */
  87.     if (!(arg & O_APPEND) && IS_APPEND(inode))
  88.         return -EPERM;
  89.  
  90.     /* Did FASYNC state change? */
  91.     if ((arg ^ filp->f_flags) & FASYNC) {
  92.         if (filp->f_op && filp->f_op->fasync)
  93.             filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
  94.     }
  95.  
  96.     /* required for strict SunOS emulation */
  97.     if (O_NONBLOCK != O_NDELAY)
  98.            if (arg & O_NDELAY)
  99.            arg |= O_NONBLOCK;
  100.  
  101.     filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
  102.     return 0;
  103. }
  104.  
  105. asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
  106. {    
  107.     struct file * filp;
  108.     long err = -EBADF;
  109.  
  110.     lock_kernel();
  111.     filp = fget(fd);
  112.     if (!filp)
  113.         goto out;
  114.     err = 0;
  115.     switch (cmd) {
  116.         case F_DUPFD:
  117.             err = dupfd(fd, arg);
  118.             break;
  119.         case F_GETFD:
  120.             err = FD_ISSET(fd, ¤t->files->close_on_exec);
  121.             break;
  122.         case F_SETFD:
  123.             if (arg&1)
  124.                 FD_SET(fd, ¤t->files->close_on_exec);
  125.             else
  126.                 FD_CLR(fd, ¤t->files->close_on_exec);
  127.             break;
  128.         case F_GETFL:
  129.             err = filp->f_flags;
  130.             break;
  131.         case F_SETFL:
  132.             err = setfl(fd, filp, arg);
  133.             break;
  134.         case F_GETLK:
  135.             err = fcntl_getlk(fd, (struct flock *) arg);
  136.             break;
  137.         case F_SETLK:
  138.             err = fcntl_setlk(fd, cmd, (struct flock *) arg);
  139.             break;
  140.         case F_SETLKW:
  141.             err = fcntl_setlk(fd, cmd, (struct flock *) arg);
  142.             break;
  143.         case F_GETOWN:
  144.             /*
  145.              * XXX If f_owner is a process group, the
  146.              * negative return value will get converted
  147.              * into an error.  Oops.  If we keep the
  148.              * current syscall conventions, the only way
  149.              * to fix this will be in libc.
  150.              */
  151.             err = filp->f_owner.pid;
  152.             break;
  153.         case F_SETOWN:
  154.             err = 0;
  155.             filp->f_owner.pid = arg;
  156.             filp->f_owner.uid = current->uid;
  157.             filp->f_owner.euid = current->euid;
  158.             if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
  159.                 err = sock_fcntl (filp, F_SETOWN, arg);
  160.             break;
  161.         case F_GETSIG:
  162.             err = filp->f_owner.signum;
  163.             break;
  164.         case F_SETSIG:
  165.             if (arg <= 0 || arg > _NSIG) {
  166.                 err = -EINVAL;
  167.                 break;
  168.             }
  169.             err = 0;
  170.             filp->f_owner.signum = arg;
  171.             break;
  172.         default:
  173.             /* sockets need a few special fcntls. */
  174.             if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
  175.                 err = sock_fcntl (filp, cmd, arg);
  176.             else
  177.                 err = -EINVAL;
  178.             break;
  179.     }
  180.     fput(filp);
  181. out:
  182.     unlock_kernel();
  183.     return err;
  184. }
  185.  
  186. static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
  187. {
  188.     struct task_struct * p;
  189.     int   pid    = fown->pid;
  190.     uid_t uid    = fown->uid;
  191.     uid_t euid    = fown->euid;
  192.     
  193.     read_lock(&tasklist_lock);
  194.     for_each_task(p) {
  195.         int match = p->pid;
  196.         if (pid < 0)
  197.             match = -p->pgrp;
  198.         if (pid != match)
  199.             continue;
  200.         if ((euid != 0) &&
  201.             (euid ^ p->suid) && (euid ^ p->uid) &&
  202.             (uid ^ p->suid) && (uid ^ p->uid))
  203.             continue;
  204.         switch (fown->signum) {
  205.             siginfo_t si;
  206.         default:
  207.             /* Queue a rt signal with the appropriate fd as its
  208.                value.  We use SI_SIGIO as the source, not 
  209.                SI_KERNEL, since kernel signals always get 
  210.                delivered even if we can't queue.  Failure to
  211.                queue in this case _should_ be reported; we fall
  212.                back to SIGIO in that case. --sct */
  213.             si.si_signo = fown->signum;
  214.             si.si_errno = 0;
  215.                 si.si_code  = SI_SIGIO;
  216.             si.si_pid   = pid;
  217.             si.si_uid   = uid;
  218.             si.si_fd    = fa->fa_fd;
  219.             if (!send_sig_info(fown->signum, &si, p))
  220.                 break;
  221.         /* fall-through: fall back on the old plain SIGIO signal */
  222.         case 0:
  223.             send_sig(SIGIO, p, 1);
  224.         }
  225.     }
  226.     read_unlock(&tasklist_lock);
  227. }
  228.  
  229. void kill_fasync(struct fasync_struct *fa, int sig)
  230. {
  231.     while (fa) {
  232.         struct fown_struct * fown;
  233.         if (fa->magic != FASYNC_MAGIC) {
  234.             printk("kill_fasync: bad magic number in "
  235.                    "fasync_struct!\n");
  236.             return;
  237.         }
  238.         fown = &fa->fa_file->f_owner;
  239.         if (fown->pid)
  240.             send_sigio(fown, fa);
  241.         fa = fa->fa_next;
  242.     }
  243. }
  244.